In many programming languages, the programmer has the illusion of allocating arbitrarily many variables while a compiler decides how to allocate these variables to specific storage areas (specific memory address or block of memory addresses) or a small, finite set of registers. However, in low-level languages and for some applications it is desirable or necessary for the programmer to specifically allocate and/or assign values to the specific storage areas and registers. Direct assignment to registers and storage areas is often done in assembly language, and in complex programs there are often low-level tasks that either can be better implemented in assembly, or can only be implemented in assembly language. Also, it is frequently useful for the programmer to look at the assembly output of a compiler, and hand-edit, or hand optimize the assembly code in ways that the compiler cannot. Assembly is also useful for time-critical or real-time processes, because unlike with high-level languages, there is no ambiguity about how the code will be compiled. The timing can be strictly controlled, which is also useful for writing simple device drivers.
Separate programs sometimes work together by referencing one another to provide a particular feature or functionality. A first program can make a “call” to a second program. The second (called) program can be another complete program, whose instructions form a logical pattern which further process information passed to it by the first program and, optionally, pass back processed information. Alternatively, the second program can be a series of unrelated statements or macros whose sole purpose is to always process information passed to it, then execute one statement which always passes information back.
When calling an external program, there is a convention that registers and control blocks (a data or storage area with a predefined structure containing the information required for the control of a task, function, or operation) in use by the calling program when the call is made are saved prior to the call and reestablished to their pre-call state or value when control is returned to the calling program. For example, registers may have been used by the calling program for storage of variable values which the calling program used prior to the transfer of control to the called program, and which the calling program may need to use when the called program returns control. The called program may not, however, need to use all of the registers for its processing, and it would be extra, perhaps unnecessary, effort to save the contents of all of these registers in memory if only some of the registers are to be used by the called program. As such, it may suffice to re-allocate only one register (or a limited number) needed by the second program. However, failure to re-allocate the one register back to its original use or value when control is returned to the calling program can lead to subsequent errors in the logic of the calling program. Tracing the source of such an error can be a difficult process as the error may not appear for a time after the control is returned to the calling program.